package com.opencee.cloud.uaa.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.opencee.cloud.base.api.IBaseApplicationApi;
import com.opencee.cloud.base.vo.BaseApplicationDetailsVO;
import com.opencee.cloud.uaa.config.UaaProperties;
import com.opencee.cloud.uaa.constants.UaaConstants;
import com.opencee.cloud.uaa.provider.service.ISocialService;
import com.opencee.common.exception.DefaultWebExceptionAdvice;
import com.opencee.common.model.ApiResult;
import com.opencee.common.utils.RedisTemplateUtil;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: liuyadu
 * @date: 2018/10/29 15:59
 * @description:
 */
@Api(tags = {"主页"})
@Slf4j
@Controller
@SessionAttributes("authorizationRequest")
public class IndexController {
    private static final String SPRING_SECURITY_LAST_EXCEPTION = "SPRING_SECURITY_LAST_EXCEPTION";
    @Autowired
    private IBaseApplicationApi appClient;
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;
    @Autowired
    private UaaProperties authProperties;
    @Autowired
    private List<ISocialService> socialServiceList;


    @ApiIgnore
    @GetMapping("/")
    public ModelAndView index() {
        return new ModelAndView("redirect:/login");
    }


    @GetMapping("/login/auth/{type}")
    public String getSocial(@PathVariable("type") String type) {
        String authorizeUrl = null;
        for (ISocialService service : socialServiceList) {
            if (service.supports(type)) {
                authorizeUrl = service.getAuthorizeUrl();
                break;
            }
        }
        if (StringUtils.isBlank(authorizeUrl)) {
            return "login";
        }
        return "redirect:" + authorizeUrl;
    }

    /**
     * 获取登录验证码
     *
     * @return
     */
    @GetMapping("/login/captcha")
    @ResponseBody
    public ApiResult<Integer> getLoginCaptcha() {
        String uuid = IdUtil.simpleUUID();
        String key = UaaConstants.CACHE_LOGIN_CAPTCHA_KEY + uuid;
        //定义图形验证码的长和宽
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        //输出code
        String code = lineCaptcha.getCode();
        //验证图形验证码的有效性，返回boolean值
        String imageBase64 = lineCaptcha.getImageBase64Data();
        redisTemplateUtil.set(key, code, 5, TimeUnit.MINUTES);
        Map<String, Object> data = new HashMap<>(2);
        data.put("rid", uuid);
        data.put("imageBase64", imageBase64);
        return ApiResult.ok().data(data);
    }

    /**
     * 获取登录二维码
     *
     * @param w
     * @param h
     */
    @GetMapping("/login/qrcode")
    @ResponseBody
    public ApiResult<Map> getLoginQrCode(HttpServletRequest request, @RequestParam(value = "w", defaultValue = "150") Integer w, @RequestParam(value = "h", defaultValue = "150") Integer h) {
        String uuid = "";
        String key = "";
        Map<String, String> data = new HashMap<>(8);
        try {
            HttpSession session = request.getSession(false);
            if (session != null) {
                uuid = SecureUtil.md5(session.getId());
            } else {
                uuid = IdUtil.simpleUUID();
            }
            String url = String.format("%s/login/qrcode/confirm_access?code=%s", authProperties.getHost(), uuid);
            log.info("生成code:{}", url);
            String status = "waiting";
            // 设置缓存
            key = UaaConstants.CACHE_LOGIN_QRCODE_KEY + uuid;
            redisTemplateUtil.set(key, status, 5, TimeUnit.MINUTES);
            QrConfig qrConfig = new QrConfig(w, h);
            qrConfig.setMargin(1);
            String imageBase64 = QrCodeUtil.generateAsBase64(url, qrConfig, "png");
            data.put("code", uuid);
            data.put("imageBase64", imageBase64);
        } catch (Exception e) {
            e.printStackTrace();
            redisTemplateUtil.del(key);
        }
        return ApiResult.ok().data(data);
    }

    /**
     * 验证登录二维码
     * 状态:invalid-已失效、waiting-等待
     *
     * @param code
     * @return
     */
    @GetMapping("/login/qrcode/check")
    @ResponseBody
    public ApiResult<Integer> checkQrCode(@RequestParam("code") String code) {
        String key = UaaConstants.CACHE_LOGIN_QRCODE_KEY + code;
        String status = redisTemplateUtil.getString(key);
        if (StringUtils.isBlank(status)) {
            status = "invalid";
        }
        return ApiResult.ok().data(status);
    }


    /**
     * 二维码登录确认页
     *
     * @param model
     * @return
     */
    @RequestMapping("/login/qrcode/confirm_access")
    public ModelAndView qrcodeConfirmAccess(Map<String, Object> model) {
        return new ModelAndView("qrcode/confirm_access", model);
    }


    /**
     * 登录页
     *
     * @return
     */
    @ApiIgnore
    @GetMapping("/login")
    public ModelAndView login(Model model, HttpServletRequest request) {
        if (request.getSession().getAttribute(SPRING_SECURITY_LAST_EXCEPTION) != null) {
            AuthenticationException exception = (AuthenticationException) request.getSession().getAttribute(SPRING_SECURITY_LAST_EXCEPTION);
            model.addAttribute("errorMessage", exception.getMessage());
            request.getSession().removeAttribute(SPRING_SECURITY_LAST_EXCEPTION);
            log.error("error", exception);
        }
        model.addAttribute("host", authProperties.getHost());
        model.addAttribute("qrEnabled", authProperties.getQrEnabled());
        model.addAttribute("smsCodeEnabled", authProperties.getSmsCodeEnabled());
        model.addAttribute("socialEnabled", authProperties.getSocialEnabled());
        return new ModelAndView("login");
    }

    /**
     * 自定义oauth2错误
     *
     * @param request
     * @return
     */
    @RequestMapping("/oauth/error")
    @ResponseBody
    public Object handleError(HttpServletRequest request, Map model) {
        Object error = request.getAttribute("error");
        return error;
    }


    /**
     * 二维码认证错误页
     *
     * @param model
     * @param request
     * @return
     */
    @GetMapping("/login/qrcode/error")
    public ModelAndView qrcodeError(Model model, HttpServletRequest request) {
        if (request.getSession().getAttribute(SPRING_SECURITY_LAST_EXCEPTION) != null) {
            AuthenticationException exception = (AuthenticationException) request.getSession().getAttribute(SPRING_SECURITY_LAST_EXCEPTION);
            model.addAttribute("errorMessage", DefaultWebExceptionAdvice.resolveException(exception, request.getRequestURI()).getBody().getMessage());
            request.getSession().removeAttribute(SPRING_SECURITY_LAST_EXCEPTION);
        }
        return new ModelAndView("qrcode/error");
    }

    /**
     * 确认授权页
     *
     * @param request
     * @param model
     * @return
     */
    @RequestMapping("/oauth/confirm_access")
    public ModelAndView confirmAccess(Map<String, Object> model, HttpServletRequest request) {
        AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest");
        String clientId = authorizationRequest.getClientId();
        BaseApplicationDetailsVO app = appClient.getByAppKey(clientId).getData();
        model.put("app", app);
        return new ModelAndView("oauth/confirm_access", model);
    }


}
